#include <stdio.h>
#include <stdlib.h>

#include "MPool.h"

/***************************************************************************************************************/
/*********************************************    MPool_UTEST    *************************************************/
/***************************************************************************************************************/
#define IS_SUCCESS(X) !X?"SUCCESS":"FAILURE"   /*  Macro to print on regression tests       */
#define IF_FAIL(X) if(X){printf("FAIL IN %s TEST, IN LINE %d\n",#X,__LINE__); return 1;}
/*******************    Forward Declerations    ******************/
int MPoolRegression_Utest();
int MPoolCreateAlloc_Utest();
int MPoolFree_Utest();
int MPoolUnused_Utest();
/*****************************************************************/

int MPoolRegression_Utest()
{
    printf("MPoolAlloc_Utest: %s\n\n", IS_SUCCESS(MPoolCreateAlloc_Utest()));
    printf("MPoolFree_Utest: %s\n\n", IS_SUCCESS(MPoolFree_Utest()));
    printf("MPoolUnused_Utest: %s\n", IS_SUCCESS(MPoolUnused_Utest()));

    return 0;
}

int main()
{
    MPoolRegression_Utest();

    return 0;
}


int MPoolCreateAlloc_Utest()
{
    int     blockSize   = 4                                         ;
    int     numBlock    = 5                                         ;
    void*   heap        = malloc(blockSize * numBlock + MP_OVERHEAD);
    MPool*  mp          = MPCreate(blockSize, numBlock ,heap)       ;
    int*    ip1         = 0                                         ;
    int*    ip2         = 0                                         ;

    IF_FAIL((void*)mp != heap)                                          /*  Check creation                                      */
    IF_FAIL(MPUnused(mp) != numBlock)                                   /*  Check the num of unused blocks                      */
    ip1 = MPAlloc(mp);
    IF_FAIL((char*)ip1 != (char*)mp + MP_OVERHEAD )                     /*  Check internal data                                 */
    IF_FAIL(*((short*)((char*)mp + MP_OVERHEAD + blockSize)) != 3)      /*  Check that the index on second block points to '3'  */
    *ip1 = 11111;
    ip2 = MPAlloc(mp);
    IF_FAIL((char*)ip2 != (char*)mp +blockSize + MP_OVERHEAD )
    IF_FAIL(MPUnused(mp) != numBlock - 2)                               /*  Check that after 2 allocations, unused = n_block -2 */
    *ip2 = 22222;
    IF_FAIL(*ip1 != 11111 || *ip2 != 22222)                             /*  Check values of alloc                               */

    return 0;
}

int MPoolFree_Utest()
{
    int     blockSize   = 4                                         ;
    int     numBlock    = 5                                         ;
    void*   heap        = malloc(blockSize * numBlock + MP_OVERHEAD);
    MPool*  mp          = MPCreate(blockSize, numBlock ,heap)       ;
    int*    ip1         = MPAlloc(mp)                               ;
    int*    ip2         = MPAlloc(mp)                               ;
    int*    ip3         = 0                                         ;

    MPFree(mp, ip1);

    *ip2 = 22222;
    IF_FAIL(MPUnused(mp) != numBlock - 1)                   /*  One allocation left                                     */
    ip3 = MPAlloc(mp);
    IF_FAIL((char*)ip3 != (char*)mp + MP_OVERHEAD)          /*  Check internal data: the new allocation on the prev one */
    IF_FAIL(MPUnused(mp) != numBlock - 2)
    ip1 = MPAlloc(mp);
    *ip1 = 11111;
    *ip3 = 3333;
    IF_FAIL(*ip1 != 11111 || *ip2 != 22222 || *ip3 != 3333)
    MPFree(mp, ip2);
    MPFree(mp, ip1);
    MPFree(mp, ip3);
    IF_FAIL(MPUnused(mp) != numBlock)                       /*  Check everyone free                                     */

    return 0;
}

int MPoolUnused_Utest()
{
    int     blockSize   = 4                                         ;
    int     numBlock    = 5                                         ;
    void*   heap        = malloc(blockSize * numBlock + MP_OVERHEAD);
    MPool*  mp          = MPCreate(blockSize, numBlock ,heap)       ;
    int*    ipArr[5]                                                ;
    int     i                                                       ;

    IF_FAIL(MPUnused(mp) != numBlock)
    for(i = 0; i < numBlock ; ++i)  /*  Allocate allblocks                  */
    {
        ipArr[i] = MPAlloc(mp);
    }
    IF_FAIL(MPUnused(mp))           /*  Check that everyone used            */

    for(i = 0; i < numBlock; ++i)
    {
        MPFree(mp , ipArr[i]);      /*  Free, then check unused updated     */
        IF_FAIL(MPUnused(mp) != i+1)
    }

    free(heap);

    return 0;
}

